﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Json;
using System.IO;

namespace DarkAjax.Utility
{
    public class jQueryAjaxUtility
    {
        public static string AjaxInvokeParam = "AjaxInvoke";
        public static string AjaxInvokeValue = "1";
        public static string ResponseCharset = "UTF-8";

        protected static System.Web.UI.Page Page
        {
            get
            {
                return System.Web.HttpContext.Current.Handler as System.Web.UI.Page;
            }
        }

        public static void RegisterAjaxInvokeScript(Type type)
        {
            jQueryInvokeMethodAttribute attr = new jQueryInvokeMethodAttribute();
            if (!jQueryUtilityCache.Current.Exists(type))
            {
                var methodinfo = type.GetMethods(System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(t =>
                {
                    var attrs = t.GetCustomAttributes(typeof(jQueryInvokeMethodAttribute), false);

                    if (attrs != null && attrs.Length > 0)
                    {
                        //attr = attrs[0] as jQueryInvokeMethodAttribute;
                        return true;
                    }
                    return false;
                }).ToList();


                if (methodinfo != null && methodinfo.Count > 0)
                {

                    System.Text.StringBuilder sb = new StringBuilder();
                    if (!string.IsNullOrEmpty(type.Namespace))
                    {
                        string[] nameSpace = type.Namespace.Split('.');
                        string currentNameSpace = "window";
                        foreach (string name in nameSpace)
                        {
                            currentNameSpace += string.Format(".{0}", name);
                            sb.AppendFormat("if (typeof({0})==\"undefined\")\n", currentNameSpace);
                            sb.Append("{\n");
                            sb.AppendFormat(" \t{0}={1};\n ", currentNameSpace, "{}");
                            sb.Append("}\n");
                        }


                    }
                    else
                    {
                        sb.Append("var");
                    }
                    sb.AppendFormat(" {0}={1};\n ", type.FullName, "{}");
                    methodinfo.ForEach(t =>
                    {
                        attr = t.GetCustomAttributes(typeof(jQueryInvokeMethodAttribute), false)[0] as jQueryInvokeMethodAttribute;
                        string url = attr.Url;
                        if (string.IsNullOrEmpty(url))
                        {
                            url = Page.Request.RawUrl.IndexOf("?") == -1 ? Page.Request.RawUrl : Page.Request.RawUrl.Substring(0, Page.Request.RawUrl.IndexOf("?"));
                        }
                        var parameters = t.GetParameters().Select(p => p.Name).ToArray();
                        sb.AppendFormat("{2}.{0} = function ({1} ajaxOption) {{\n", t.Name, parameters.Count() > 0 ? string.Join(",", parameters) + "," : "", type.FullName);
                        sb.Append("\t var result;\n\t if(ajaxOption==null||typeof ajaxOption==\"undefined\"){\n\t\t ajaxOption={};\n\t};\n");
                        sb.Append("\t var options = {};\n");
                        sb.AppendFormat("\t options.url = \"{0}\";\n", url);
                        sb.AppendFormat("\t options.async = {0};\n", attr.Async.ToString().ToLower());
                        sb.AppendFormat("\t options.type = \"{0}\";\n", attr.Method);
                        sb.AppendFormat("\t options.cache = {0};\n", attr.Cache.ToString().ToLower());
                        sb.AppendFormat("\t options.dataType =\"{0}\";\n", attr.DataType);
                        sb.Append("\t options.success=function(e){ \n\t\t result=e; \n\t }; \n");
                        sb.Append("\t options.data ={ \n");

                        foreach (string s in parameters)
                        {
                            sb.AppendFormat("\t\t {0}:JSON.stringify({1}), \n", s, s);
                        }

                        sb.AppendFormat("\t\t _method:\"{0}\", \n", t.Name);
                        sb.AppendFormat("\t\t _class:\"{0}\", \n", type.Name);
                        sb.AppendFormat("\t\t {0}:\"{1}\" \n", AjaxInvokeParam, AjaxInvokeValue);
                        sb.Append("\t }; \n");

                        //sb.AppendFormat("\t options.data = 'method={1}&{2}={3}&class={4}'+{0}; \n", data, t.Name, AjaxInvokeParam, AjaxInvokeValue, type.Name);

                        sb.Append("\t jQuery.extend(options,ajaxOption); \n");
                        sb.Append("\t jQuery.ajax(options); \n\t return result; \n};\n");

                    });

                    //var min = new JavascriptMinifier();
                    //min.VariableMinification = VariableMinification.LocalVariablesOnly;

                    jQueryUtilityCache.Current.AddScript(type, sb.ToString());
                }
            }
            var script = jQueryUtilityCache.Current.GetScript(type);
            Page.ClientScript.RegisterClientScriptBlock(type.GetType(), type.FullName + "_" + typeof(jQueryAjaxUtility).FullName + "_AjaxInvoke", script, true);
        }

        protected string GenertorScript(Type type)
        {

            return string.Empty;
        }

        public static void RegisterAjaxInvokeEvent(Type type)
        {
            var Request = System.Web.HttpContext.Current.Request;
                var Response = System.Web.HttpContext.Current.Response;
            //try
            //{
                
                var method = Request["_method"];
                if (string.IsNullOrEmpty(method))
                    return;
                Response.Clear();
                var methodinfo = type.GetMethod(method, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
                if (methodinfo != null)
                {
                    Response.Charset = ResponseCharset;
                    Response.ContentType = string.Join(",", Request.AcceptTypes);
                    var param = methodinfo.GetParameters();
                    object[] objs = new object[param.Length];
                    var i = 0;
                    param.ToList().ForEach(t =>
                    {
                        objs[i++] = AjaxPro.JavaScriptDeserializer.DeserializeFromJson(Request[t.Name], t.ParameterType);

                    });

                    var obj = methodinfo.Invoke(null, objs);
                    if (obj != null)
                    {
                        //序列化
                        if (!obj.GetType().IsValueType && obj.GetType() != typeof(string))
                        {
                            if (Request.AcceptTypes.Contains("text/xml"))
                            {
                                Response.Write(DarkAjax.Utility.SerializerUtility.XmlSerializer(obj));
                            }
                            else if (Request.AcceptTypes.Contains("application/json"))
                            {
                                Response.ContentType = "application/json, text/javascript, */*";
                                Response.Write(AjaxPro.JavaScriptSerializer.Serialize(obj));
                            }
                            else
                            {
                                Response.Write(obj);
                            }

                        }
                        else
                        {
                            Response.Write(obj);
                        }
                    }

                    Response.Flush();
                    Response.Close();
                    Response.End();
                }
            //}
            //catch (Exception ex)
            //{
            //    Response.Write(ex.Message);
            //}
            
        }


    }
}
